/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jsinterfacesample.android.chrome.google.com.jsinterface_example; import android.annotation.TargetApi; import android.app.Fragment; import android.content.Intent; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.util.JsonReader; import android.util.JsonToken; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; import java.io.IOException; import java.io.StringReader; /** * Created by mattgaunt on 10/16/14. */ public class MainFragment extends Fragment { public static final String EXTRA_FROM_NOTIFICATION = "EXTRA_FROM_NOTIFICATION"; private WebView mWebView; public MainFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); // Get reference of WebView from layout/activity_main.xml mWebView = (WebView) rootView.findViewById(R.id.fragment_main_webview); // Add Javascript Interface, this will expose "window.NotificationBind" // in Javascript mWebView.addJavascriptInterface( new NotificationBindObject(getActivity().getApplicationContext()), "NotificationBind"); setUpWebViewDefaults(mWebView); // Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) { // Restore the previous URL and history stack mWebView.restoreState(savedInstanceState); } // Prepare the WebView and get the appropriate URL String url = prepareWebView(mWebView.getUrl()); // Load the local index.html file if(mWebView.getUrl() == null) { mWebView.loadUrl(url); } return rootView; } /** * Convenience method to set some generic defaults for a * given WebView * * @param webView */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void setUpWebViewDefaults(WebView webView) { WebSettings settings = webView.getSettings(); // Enable Javascript settings.setJavaScriptEnabled(true); // Use WideViewport and Zoom out if there is no viewport defined settings.setUseWideViewPort(true); settings.setLoadWithOverviewMode(true); // Enable pinch to zoom without the zoom buttons settings.setBuiltInZoomControls(true); if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) { // Hide the zoom controls for HONEYCOMB+ settings.setDisplayZoomControls(false); } // Enable remote debugging via chrome://inspect if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { WebView.setWebContentsDebuggingEnabled(true); } } /** * This is method where specific logic for this application is going to live * @return url to load */ private String prepareWebView(String currentUrl) { String hash = ""; int bgColor; if(currentUrl != null) { String[] hashSplit = currentUrl.split("#"); if(hashSplit.length == 2) { hash = hashSplit[1]; } } else { Intent intent = getActivity().getIntent(); if(intent != null && intent.getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) { hash = "notification-launch"; } } if(hash.equals("notification-launch")) { bgColor = Color.parseColor("#1abc9c"); } else if(hash.equals("notification-shown")) { bgColor = Color.parseColor("#3498db"); } else if(hash.equals("secret")) { bgColor = Color.parseColor("#34495e"); } else { bgColor = Color.parseColor("#f1c40f"); } preventBGColorFlicker(bgColor); // We set the WebViewClient to ensure links are consumed by the WebView rather // than passed to a browser if it can mWebView.setWebViewClient(new WebViewClient()); return "file:///android_asset/www/index.html#"+hash; } /** * This is a little bit of trickery to make the background color of the UI * the same as the anticipated UI background color of the web-app. * * @param bgColor */ private void preventBGColorFlicker(int bgColor) { ((ViewGroup) getActivity().findViewById(R.id.activity_main_container)).setBackgroundColor(bgColor); mWebView.setBackgroundColor(bgColor); } /** * This method is designed to hide how Javascript is injected into * the WebView. * * In KitKat the new evaluateJavascript method has the ability to * give you access to any return values via the ValueCallback object. * * The String passed into onReceiveValue() is a JSON string, so if you * execute a javascript method which return a javascript object, you can * parse it as valid JSON. If the method returns a primitive value, it * will be a valid JSON object, but you should use the setLenient method * to true and then you can use peek() to test what kind of object it is, * * @param javascript */ public void loadJavascript(String javascript) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // In KitKat+ you should use the evaluateJavascript method mWebView.evaluateJavascript(javascript, new ValueCallback<String>() { @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public void onReceiveValue(String s) { JsonReader reader = new JsonReader(new StringReader(s)); // Must set lenient to parse single values reader.setLenient(true); try { if(reader.peek() != JsonToken.NULL) { if(reader.peek() == JsonToken.STRING) { String msg = reader.nextString(); if(msg != null) { Toast.makeText(getActivity().getApplicationContext(), msg, Toast.LENGTH_LONG).show(); } } } } catch (IOException e) { Log.e("TAG", "MainActivity: IOException", e); } finally { try { reader.close(); } catch (IOException e) { // NOOP } } } }); } else { /** * For pre-KitKat+ you should use loadUrl("javascript:<JS Code Here>"); * To then call back to Java you would need to use addJavascriptInterface() * and have your JS call the interface **/ mWebView.loadUrl("javascript:"+javascript); } } public boolean goBack() { if(!mWebView.canGoBack()) { return false; } mWebView.goBack(); return true; } }